home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-02
/
fsortm.zip
/
FSORTM.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-01-04
|
10KB
|
282 lines
Page 80,132
Title 'FSORT - Multi-key Shell/Metzner Sort of in core array'
;
; Preparing FSORT.BIN :
;
; MASM FSORTM;
; LINK FSORTM;
; EXE2BIN FSORTM
; DEL FSORTM.EXE
;
; Original sorting code written for SORTF version 1.7 by Vern Buerg
;
; Modified to fully relocatable code suitable for use as an external
; subprogram to a Turbo Pascal program and to support multiple
; sort keys.
; by
; David Gwillim
; 29 July 1985
;
; ******************************
;
; Turbo Pascal Usage:
;
; const
; MAXKEYS = (however many keys you will use) ;
;
; type
; KeyType = array[1..MAXKEYS] of integer ;
;
; procedure Sort(RecLen : integer ; {Size of each array record }
; NumKeys : integer ; {Number of sort keys being used}
; var KeyPos : KeyType ; {Array of sort key positions }
; var KeyLen : KeyType ; {Array of sort key lengths }
; RecCnt : integer ; {Number of records to sort }
; Base : integer ) ; {Segment address of array }
; external 'FSORTM.BIN' ;
;
; IMPORTANT NOTE:
; This version of FSORTM is designed for use with arrays created on Turbo's
; Heap using the "New" or "GetMem" procedures. It is NOT designed to be used
; with arrays that are defined in Turbo Pascal's Data Segment, or anywhere
; where the array to be sorted cannot for sure be made to start on a paragraph
; (16 byte) boundary in the 8088/8086 address space. This is a compromise that
; permits very high speed sorting.
;
; Also the size of RecLen MUST be a multiple of 16 bytes otherwise
; unpredictable happenings will occur during the sort. The sort routine
; depends for its operation on the records being adressable with the just
; 8088 segment registers. As a result the base address of the array
; must have an offset divisible by 16, i.e. the address of the array must be
; on a paragraph (16 byte) boundary in the 8088 adress space.
; This is guaranteed by the "New" procedure in Turbo Pascal if the sort
; array is the FIRST variable allocated memory space on the heap.
; Although not covered in the Turbo Pascal Reference Manual the minimum
; allocation unit that either "New" or "GetMem" uses is 8 bytes.
;
; Therefore, byte allocations on Turbo's heap go like this:
;
; Variable Size in bytes Allocation in bytes
; ---------------------- -------------------
;
; 1 - 8 8
; 9 - 16 16
; 17 - 24 24
; 25 - 32 32
; etc. etc.
;
; So, the current offset of the predefined variable "HeapPtr" can be
; checked to see if it zero, and if it isn't, allocate a pointer to type
; byte before allocating for the array to be sorted. This would only be needed
; if there had been a previous use of "GetMem" and/or "New" in the program.
; It can easily done like this:
;
; var
; BytePtr : ^byte ;
;
; if Ofs(HeapPtr^) <> 0 then
; New(BytePtr) ;
;
; *******************************
;
Cseg Segment
Assume CS:Cseg,DS:Nothing,ES:Nothing
; Equates for passed parameters from the Turbo Pascal program
RecLen Equ Word Ptr [BP + 20] ;Size of each entry (mod 16 must = 0)
NumKeys Equ Word Ptr [BP + 18] ;Number of keys being used in the sort
SKeyPos Equ Word Ptr [BP + 16] ;Segment of key offset array
OKeyPos Equ Word Ptr [BP + 14] ;Offset of key offset array
SKeyLen Equ Word Ptr [BP + 12] ;Segment of key length array
OKeyLen Equ Word Ptr [BP + 10] ;Offset of key length array
RecCnt Equ Word Ptr [BP + 08] ;Number of entries
Base Equ Word Ptr [BP + 06] ;Seg addr of array
; Equates for Stack addressing
DSeg Equ Word Ptr [BP + 04] ;Turbo's DSeg value
WorkArea Equ 20 ;Allocation size for local work area
; Equates for local work area variables
Loc Equ Word Ptr [BP - 02] ;Array location record number
SegLen Equ Word Ptr [BP - 04] ;Paras in each entry
Limit Equ Word Ptr [BP - 06] ;Temporary work variables for Sort
Incr Equ Word Ptr [BP - 08]
Index1 Equ Word Ptr [BP - 10]
Index2 Equ Word Ptr [BP - 12]
Ptr1 Equ Word Ptr [BP - 14] ;Offset to record Index1
Ptr2 Equ Word Ptr [BP - 16] ;Offset to record Index2
CurrKey Equ Word Ptr [BP - 18] ;Current key being sorted on
TempOfs Equ Word Ptr [BP - 20] ;Offset to sort exchange area
; The temporary storage space for record exchanges exists in a work area
; beneath TempOfs, the size of which is determined at run-time and the offset
; to it placed in TempOfs.
CR Equ 13
LF Equ 10
Sort Proc Near
Jmp short Start
Version db CR
db 'FSORT - MULTIKEY ' ;^Z at end so version number can be
db 'V 1.01',CR,LF ; can be shown by TYPE FSORTM.BIN
db 'Copyright (C) 1985 ' ; from DOS
db 'by David Gwillim',26
Start: Cld ;Make sure we are incrementing indexes
Push DS ;Save Turbo environment
Push BP
Mov BP,SP ;Make parameters on stack addressable
Mov AX,WorkArea ;Make space on stack for sort vars
Add AX,RecLen ; and sort exchange variable
Sub SP,AX
Mov TempOfs,SP ;Store offset to sort exchange var
Mov AX,RecCnt ;Set initial value for Loc = RecCnt
Mov Loc,AX
Mov AX,RecLen ;Calculate number of 16 byte
Mov CL,4 ; paragraphs in each record
Shr AX,CL
Mov SegLen,AX
Check: Cmp Loc,1 ;Check if Loc <= 1
Jg Check1 ;If not continue
Jmp Sorted ;If so, we're done, go clean up and
; return to Turbo Pascal program
Check1: Mov AX,Loc ;Calculate a new value for Loc
Sar AX,1
Or AX,1
Mov Loc,AX ;New value for Loc = 2 * (Loc/4) + 1
Mov AX,RecCnt ;Calculate the new value for Limit
Sub AX,Loc
Mov Limit,AX ;Update value: Limit = RecCnt - Loc
Mov Incr,0 ;Incr=0
Again: Mov CurrKey,0 ;Make sure we use first key when
Jmp short Cont ; first comparing arrays
Next1: Inc CurrKey ;Tie on CurrKey compare so go to next
Inc CurrKey ; key by indexing to next array value
Mov BX,NumKeys ;Allow for KeyType array (2 bytes)
Shl BX,1 ; for each KeyPos stored
Cmp CurrKey,BX ;Already sorted on the final key?
Jbe Next2 ;If so, go sort on the next key
Jmp Again ;No more keys, leave records where-is
; and go compare two other records
Cont: Inc Incr ;Incr=Incr+1
Mov AX,Incr ;Ensure we are still in array bounds
Cmp AX,Limit ;If Incr > Limit then goto Check
Jg Check
Mul SegLen ;Allow for record length
Mov Index1,AX ;New value for Index1 = Incr * SegLen
Mov Index2,AX ;Compute new value for Index2
Mov AX,Loc ;for next compare
Mul SegLen ;Allow for record length
Add Index2,AX ;New value for Index2
; = Index1 + (Loc * SegLen)
; Compare the record keys in Array[Index1] and Array[Index2]
Comp: Mov AX,Index1
Sub AX,SegLen ;Decrement by length of one record
Add AX,Base ;Compute the segment address
Mov ES,AX ;Segment address for Index1
Mov Ptr1,AX ;Update stored value for Index1
Mov AX,Index2 ;Decrement by length of one record
Sub AX,SegLen ;Compute the segment address
Add AX,Base ;Segment address for Index2
Mov Ptr2,AX ;Update stored value for Index2
; Get the offsets, within the records, of the keys currently being compared
Next2: Mov DS,SKeyLen ;Get segment address of KeyLen array
Mov SI,OKeyLen ;Get offset address of KeyLen array
Add SI,CurrKey ;Use CurrKey's length
Mov CX,DS:[SI] ;Get KeyLen[CurrKey+1] from Turbo
Mov DS,SKeyPos ;Get segment address of KeyPos array
Mov DI,OKeyPos ;Point DI to offset of KeyPos array
Add DI,CurrKey ;Use CurrKey's offset
Mov DI,DS:[DI] ;Get KeyPos[CurrKey + 1] from Turbo
Dec DI ;Turn key position into key offset
Mov SI,OKeyPos ;Point SI to offset of KeyPos array
Add SI,CurrKey ;Make index to CurrKey's offset value
Mov SI,DS:[SI] ;Get KeyPos[CurrKey+1] from Turbo
Dec SI ;Turn key position into key offset
Mov DS,AX ;Get the segment address for Index2
Repe Cmpsb ;Compare the two keys
Ja Again ;The compared keys are in order
Je Next1 ;Keys are equal so check for next key
; Fall through if Array[Index1] < Array[Index2] - keys not in order
Mov CurrKey,0 ;Make sure we use first key next time
; Keys were not in order, exchange the records Array[Index1] and Array[Index2]
Swap: Mov AX,SS ;Temporary storage is located in the
Mov ES,AX ; Stack Segment - point to it
Mov DI,TempOfs ;Get offset of temp storage record
Mov CX,Reclen ;Get number of bytes to move
Mov DS,Ptr1 ;Get segment address of Array[Index1]
Sub SI,SI ;Ensure we at beginning of the record
Rep Movsb ;Move Array[Index1] to temporary
; storage
Mov ES,Ptr1 ;Get segment address of Array[Index1]
Mov DS,Ptr2 ;Get segment address of Array[Index2]
Sub DI,DI ;Ensure we at beginning of the records
Sub SI,SI
Mov CX,Reclen ;Get number of bytes to move
Rep Movsb ;Move Array[Index2] into Array[Index1]
Mov AX,SS ;Temp exchange record is in stack seg
Mov DS,AX ;Source segment = Temp exchange record
Mov SI,TempOfs ;Point to Temp sort exchange space
Mov ES,Ptr2 ;Destination segment = Ptr2
Sub DI,DI ;Make sure we start at beginning
Mov CX,Reclen ;Get number of bytes to move
Rep Movsb ;Move Temp to Array[Index2]'s location
Mov AX,Index1 ;Make Index2 = Index1
Mov Index2,AX
Mov AX,Loc ;Index1=Index1-Loc
Mul SegLen ;Allow for record length
Sub Index1,AX ;Update value for Index1
Jg GoComp ;Is Index1 > 0 then
Jmp Again ; no, then go to Again
GoComp: Jmp Comp ; yes, go compare keys
Sorted: Mov SP,BP ;Restore Turbo environment
Pop BP
Pop DS
Ret 16 ;Dump the passed parameters
; and return to Turbo program
Sort Endp
Cseg Ends
End Sort